﻿using System;
using System.ComponentModel;
using System.IO;
using System.Linq;
//using Newtonsoft.Json;
using System.Text.Json.Serialization;
using FFmpegVideoClip.Configuration;
using FFmpegVideoClip.Lib;
using PropertyChanged;

namespace FFmpegVideoClip
{
    [AddINotifyPropertyChangedInterface]
    public class Fragment : INotifyPropertyChanged
    {
        public enum ShowTimeModeEnum { TimeFormat, TotalSeconds, TotalMinutes }
        public static readonly ShowTimeModeEnum[] m_ShowTimeModeAll = Enum.GetValues<ShowTimeModeEnum>();
        public static ShowTimeModeEnum[] ShowTimeModeAll => m_ShowTimeModeAll;

        public event PropertyChangedEventHandler? PropertyChanged;
        public void CallPropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
        [JsonIgnore] public bool IsSelected { get; set; }
        [JsonIgnore]public Clip? clip { get; set; }
        public int ID { get; set; } = -1;
        public int Index { get; set; } = -1;
        private string m_name = string.Empty;
        [DoNotCheckEquality] public string Name { get => m_name; set { Tools.TrimInvalidFileNameChars(ref value); if (m_name.Equals(value)) return; m_name = value; } }
        private string _InputPath = string.Empty;
        public string InputPath { get => _InputPath;
            set {
                if (_InputPath.Equals(value, StringComparison.OrdinalIgnoreCase))
                    return;
                _InputPath = value;
                GetMediaInfo.MediaInfoResult _info = GetMediaInfo.GetInfo(value);
                Width = _info.Width;
                Height = _info.Height; 
            }}
        [JsonIgnore] public string InputFileExtension => Path.GetExtension(InputPath);
        public string StartTimeValue { get; set; } = TextBoxTextTimeInputChangedLimit.DefaultHistorical;
        public string EndTimeValue { get; set; } = TextBoxTextTimeInputChangedLimit.DefaultHistorical;

        public bool IsVideoStream { get; set; } = false;
        public bool IsAudioStream { get; set; } = false;
        public bool IsSubStream { get; set; } = false;

        [JsonIgnore] public string TempWritePath = string.Empty;

        [JsonIgnore] public TimeSpan FragmentDuration => Tools.GetStringTimeToTimeSpan(EndTimeValue) - Tools.GetStringTimeToTimeSpan(StartTimeValue);
        [JsonIgnore] private string IncrementTime
        {
            get
            {
                if (clip == null || clip.Fragments == null || clip.Fragments.Count < 1)
                    return string.Empty;
                TimeSpan SumTime = clip.Fragments.Take(clip.IndexOf(this) + 1).Select(p => p.FragmentDuration).Sum();
                return Config.CurrentShowTimeMode switch
                {
                    ShowTimeModeEnum.TotalSeconds => SumTime.TotalSeconds.ToString(),
                    ShowTimeModeEnum.TotalMinutes => SumTime.TotalMinutes.ToString(),
                    _ => Tools.GetStringTimeTrimZero(SumTime)
                };
            }
        }
        [JsonIgnore] public string TimeRangeShow => $"{Tools.GetStringTimeTrimZero(StartTimeValue)}<->{Tools.GetStringTimeTrimZero(EndTimeValue)}|[{Tools.GetStringTimeTrimZero(FragmentDuration)}]|[{IncrementTime}]";
        [JsonIgnore] public int Width { get; private set; }
        [JsonIgnore] public int Height { get; private set; }
        [JsonIgnore] public string Width_Height_String => Width < 1 || Height < 1 ? string.Empty : $"{Width}×{Height}";
        public void CopyTo(Fragment fragment)
        {
            fragment.clip = clip;
            fragment.ID = ID;
            fragment.Name = Name;
            fragment._InputPath = _InputPath;
            fragment.PropertyChanged?.Invoke(fragment, new PropertyChangedEventArgs(nameof(InputPath)));
            fragment.StartTimeValue = StartTimeValue;
            fragment.EndTimeValue = EndTimeValue;
            fragment.TempWritePath = TempWritePath;
            fragment.IsVideoStream = IsVideoStream;
            fragment.IsAudioStream = IsAudioStream;
            fragment.IsSubStream = IsSubStream;
            fragment.Width = Width;
            fragment.Height = Height;
        }

        public void CopyToSet(Fragment fragment)
        {
            clip = fragment.clip;
            Name = fragment.Name;
            ID = fragment.ID;
            _InputPath = fragment._InputPath;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(InputPath)));
            StartTimeValue = fragment.StartTimeValue;
            EndTimeValue = fragment.EndTimeValue;
            TempWritePath = fragment.TempWritePath;
            IsVideoStream = fragment.IsVideoStream;
            IsAudioStream = fragment.IsAudioStream;
            IsSubStream = fragment.IsSubStream;
            Width = fragment.Width;
            Height = fragment.Height;
        }

        public Fragment CloneNewFragment()
        {
            Fragment fragment = new Fragment();
            CopyTo(fragment);
            return fragment;
        }

        public void GenerateTempWritePath()
        {
            if (clip is null)
                throw new NullReferenceException($"[{Name}]片段不与任何剪辑关联");
            string FileName = Path.GetFileName(clip.FileWritePath);
            if (string.IsNullOrEmpty(FileName))
                throw new ArgumentException($"[{clip.Name}],写入路径没有有效的文件名");
            string m_Extension = Path.GetExtension(FileName);
            FileName = Path.GetFileNameWithoutExtension(FileName) + $"Clip_Fragment_[{Name}]";
            string m_path = Path.Combine(Config.CacheDirectory, clip.Name);
            if (!Directory.Exists(m_path))
                Directory.CreateDirectory(m_path);
            TempWritePath = Path.Combine(m_path, FileName + m_Extension);
        }

        public string GetFileWritePath()
        {
            if (string.IsNullOrEmpty(TempWritePath))
                throw new NullReferenceException($"[{Name}]片段写入路径不存在");
            if (!File.Exists(TempWritePath))
                throw new FileNotFoundException($"[{TempWritePath}]文件不存在");
            return TempWritePath;
        }
    }

}
